package com.note.simpleshop.module.coupon.service;

import com.note.simpleshop.constant.DeleteConstant;
import com.note.simpleshop.entity.TbClassify;
import com.note.simpleshop.entity.TbCoupon;
import com.note.simpleshop.entity.TbGivedCoupon;
import com.note.simpleshop.exception.ExceedsLimitException;
import com.note.simpleshop.exception.NotDataException;
import com.note.simpleshop.exception.NotDataTypeException;
import com.note.simpleshop.module.coupon.dao.CouponRepository;
import com.note.simpleshop.module.coupon.dao.GivedCouponRepository;
import com.note.simpleshop.module.coupon.dto.CouponDto;
import com.note.simpleshop.module.coupon.vo.CouponVo;
import com.note.simpleshop.module.goods.dao.ClassifyRepository;
import com.note.simpleshop.redis.RedisLock;
import com.note.simpleshop.utils.ClassUtils;
import com.note.simpleshop.utils.DateUtil;
import com.note.simpleshop.utils.IdGenerator;
import com.note.simpleshop.vo.PageBean;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.sql.Delete;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import sun.rmi.runtime.Log;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class CouponService implements Serializable {
    private final Logger logger = LoggerFactory.getLogger(CouponService.class);
    private static final String CACHE_NAME = "coupon_cache";
    @Autowired
    private CouponRepository couponRepository;
    @Autowired
    private GivedCouponRepository givedCouponRepository;
    @Autowired
    private RedisLock redisLock;
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public Integer getDrawedCount(String drawerId, String couponId) {
        return givedCouponRepository.countByUserIdAndCouponId(drawerId,couponId).intValue();
    }
    public TbCoupon findByActive(String couponId) {
        TbCoupon tbCoupon = couponRepository.findByIdAndActiveAndIsDelete(couponId,TbCoupon.ACTIVED, DeleteConstant.NORM);
        return tbCoupon;
    }
    /**
     *
     *
     * 用户领取优惠劵信息
     * @param userId
     * @param couponId
     */
    public void give(String userId,String couponId,String requestId) throws NotDataException,ExceedsLimitException,Exception{
        //获取锁
        if(redisLock.tryLock(couponId,requestId)) {
            try {
                TbCoupon tbCoupon = this.findByActive(couponId);
                if (tbCoupon == null) {
                    throw new NotDataException("优惠劵不存在");
                }
                //判断优惠劵是否已经领取完毕
                if(tbCoupon.getTotal()-tbCoupon.getDrawed()<=0) {
                    throw new ExceedsLimitException("优惠劵已领完");
                }
                //判断用户是否超出领取限制
                Integer drawLimit = tbCoupon.getDrawLimit();
                Integer drawedCount = this.getDrawedCount(userId, couponId);
                if (drawedCount <= drawLimit) {
                    //领取优惠劵
                    Integer total = tbCoupon.getTotal();
                    tbCoupon.setDrawed(tbCoupon.getDrawed()+1);
                    TbGivedCoupon givedCoupon = new TbGivedCoupon();
                    givedCoupon.setId(IdGenerator.id());
                    givedCoupon.setGiveTime(new Date());
                    givedCoupon.setUserId(userId);
                    givedCoupon.setCouponId(couponId);
                    //根据不同时间类型优惠劵计算优惠劵有效时间
                    String dateType=tbCoupon.getDateType();
                    //固定时间段
                    if(TbCoupon.INTERVAL.equals(dateType)) {
                        givedCoupon.setEifTime(tbCoupon.getEifTime());
                        givedCoupon.setExpireTime(tbCoupon.getExpireTime());
                    }
                    //领取后n天
                    else if(TbCoupon.COUNT_DOWN.equals(dateType)) {
                        givedCoupon.setEifTime(tbCoupon.getEifTime());
                        givedCoupon.setExpireTime(DateUtil.after(tbCoupon.getCountDownDay()));
                    }
                    else {
                        logger.error("dateType类型不存在");
                        throw new NotDataTypeException("dateType类型不存在");
                    }
                    givedCouponRepository.save(givedCoupon);
                    couponRepository.save(tbCoupon);
                } else {
                    throw new ExceedsLimitException("每人最多领取"+drawLimit+"张");
                }
            }
            finally {
                redisLock.releaseLock(couponId,requestId);
            }
        }
        else {
            throw new Exception("领取人数太多");
        }

    }

    /**
     *
     * 根据频道值获取优惠劵信息
     * @param channel
     * @return
     */
    public List<TbCoupon> findByChannel(String channel) {
        return couponRepository.findByChannelAndIsDeleteOrderByIdDesc(channel, DeleteConstant.NORM);
    }
    public PageBean<CouponVo> findByPage(CouponDto dto) throws NotDataTypeException {
        if(dto.getPageNumber()==null) {
            dto.setPageNumber(1);
        }
        if(dto.getLimit()==null) {
            dto.setLimit(20);
        }
        StringBuilder dataSql=new StringBuilder().append("select g.id,g.give_time as giveTime,g.user_id as userId,c.`name` as couponName,c.preferential_way as preferentialWay,c.discount," +
                "c.quota,c.overlying,c.remark,c.restriction_money as restrictionMoney,g.eif_time as eifTime,g.expire_time as expireTime " +
                "from tb_gived_coupon g , tb_coupon c where g.coupon_id=c.id and g.user_id=? and g.usage_state=? limit ?,? ");
        StringBuilder countSql = new StringBuilder("select count(1) from tb_gived_coupon g,tb_coupon c where g.coupon_id=c.id and g.user_id=? and g.usage_state=?");
        if(!CouponDto.SET.contains(dto.getState())) {
            throw new NotDataTypeException("类型不存在");
        }
        //未使用优惠劵且没有过期的
        if(CouponDto.UN_USED.equals(dto.getState())) {
            dataSql.append(" and  g.expire_time>=now()");
        }
        if(CouponDto.EXPIRED.equals(dto.getState())) {
            dataSql.append(" and  g.expire_time<now()");
        }
        List<Object> dataParameters=new ArrayList<Object>();
        List<Object> countParameters=new ArrayList<Object>();
        dataParameters.add(dto.getUserId());
        countParameters.add(dto.getUserId());
        //已经使用
        if(dto.getState().equals(CouponDto.USED)) {
            dataParameters.add(1);
            countParameters.add(1);
        }
        //未使用
        else if(dto.getState().equals(CouponDto.UN_USED)) {
            dataParameters.add(0);
            countParameters.add(0);
        }
        //已经过期
        else if(dto.getState().equals(CouponDto.EXPIRED)) {
            dataParameters.add(0);
            countParameters.add(0);
        }
        Integer startIndex=(dto.getPageNumber()-1)*dto.getLimit();
        dataParameters.add(startIndex);
        dataParameters.add(dto.getLimit());
        List<CouponVo> list=jdbcTemplate.query(dataSql.toString(), dataParameters.toArray(), new RowMapper<CouponVo>() {
            @Override
            public CouponVo mapRow(ResultSet resultSet, int i) throws SQLException {
                return (CouponVo) ClassUtils.getInstance(CouponVo.class,resultSet);
            }
        });
        Integer total=jdbcTemplate.queryForObject(countSql.toString(),countParameters.toArray(),Integer.class);
        //计算总页数
        Integer totalPages=total%dto.getLimit()==0?total/dto.getLimit():(total/dto.getLimit()+1);
        return new PageBean(totalPages,total,dto.getPageNumber()==1,list.isEmpty(),dto.getPageNumber(),list);
    }

    public List<CouponVo> findByCoupon(String userId,List<String> couponIds) {
        StringBuilder dataSql=new StringBuilder().append("select g.id,g.give_time as giveTime,g.user_id as userId,c.id as couponId,c.`name` as couponName,c.preferential_way as preferentialWay,c.discount," +
                "c.quota,c.overlying,c.remark,c.restriction_money as restrictionMoney,g.eif_time as eifTime,g.expire_time as expireTime " +
                "from tb_gived_coupon g , tb_coupon c where g.coupon_id=c.id and g.user_id=? and g.usage_state=? and g.id in(?) g.expire_time>=now()");
        List<Object> dataParameters=new ArrayList<Object>();
        dataParameters.add(userId);
        //未使用
        dataParameters.add(0);
        //防止为空
        couponIds.add("0");
        dataParameters.add(couponIds);
        List<CouponVo> list=jdbcTemplate.query(dataSql.toString(), dataParameters.toArray(), new RowMapper<CouponVo>() {
            @Override
            public CouponVo mapRow(ResultSet resultSet, int i) throws SQLException {
                return (CouponVo) ClassUtils.getInstance(CouponVo.class,resultSet);
            }
        });
        return list;
    }
}
